import 'antd/dist/antd.css';
import './App.css';
import 'react-chat-elements/dist/main.css';

import React from 'react';
import { MessageList } from 'react-chat-elements'
import Avatars from '@dicebear/avatars';
import sprites from '@dicebear/avatars-avataaars-sprites';
import { message as AntMessage, Modal, Input } from 'antd';

var websocket: WebSocket;

class Data {
  position: string = '';
  type: string = '';
  avatar: string = '';
  title: string = '';
  text: string = '';
  date: Date = new Date();
}

type What = '' | 'login' | 'logout' | 'sendMsg' | 'onlineUsers' | 'new_chat_msg' | 'friend_logged_out' | 'friend_logged_in';

class Message {
  what: What = '';
  sender: string = '';
  content: string = '';
  rsp: string = '';
  timestamp: number = 0;
}

class SendMessage {
  constructor(what: What, content: string) {
    this.what = what;
    this.content = content;
  }
  what: What;
  content: string;
}

class State {
  connected: boolean = false;
  dataSource: Data[] = [];
  modalVisible: boolean = true;
  nickname: string = '';
  message: string = '';
}

class App extends React.Component<any, State> {
  constructor(props: any) {
    super(props)
    this.state = new State()
    this.init()
  }

  render() {
    return (
      <div className="App">
        <div className="chatList">
          <MessageList
            className='message-list'
            lockable={true}
            toBottomHeight='100%'
            dataSource={this.state.dataSource} />
          <div style={{ height: 0 }}>
            <a className="toBottom" id="1" href="#1">&nbsp;</a>
          </div>
        </div>
        <div className="inputArea">
          <input id="textbox" type="text" value={this.state.message}
            onChange={(e) => { this.setState({ message: e.target.value }) }}
            onKeyDown={(e) => { if (e.keyCode === 13) { this.sendChatMessage() } }}
          />
          < button id="submit" onClick={() => { this.sendChatMessage() }}>发送</button>
        </div>

        {/* ------------------------------------------------------------------------------------- */}
        <Modal
          title="登录"
          closable={false}
          visible={this.state.modalVisible}
          cancelButtonProps={{ disabled: true }}
          onOk={() => { this.tryLogin() }}
          cancelText="取消"
          okText="确认"
        >
          <Input placeholder="请输入你的昵称" value={this.state.nickname}
            onChange={(e) => { this.setState({ nickname: e.target.value }) }}
            onKeyDown={(e) => { if (e.keyCode === 13) { this.tryLogin() } }}
          />
        </Modal>
      </div>
    )
  }

  init() {
    if ("WebSocket" in window) {
      const protocol = window.location.protocol;
      let websocketProt;
      if (protocol === 'http:') {
        websocketProt = 'ws:'
      } else {
        websocketProt = 'wss:'
      }
      const baseURL = websocketProt + '//' + window.location.host
      const websocketURL = baseURL + '/service/websocket/vchat'
      websocket = new WebSocket(websocketURL)
      websocket.onopen = (e) => { this.onOpen(e) }
      websocket.onclose = (e) => { this.onClose(e) }
      websocket.onerror = (e) => { this.onError(e) }
      websocket.onmessage = (e) => { this.onMessage(e) }
    } else {
      alert('你的浏览器不支持WebSocket!')
    }
  }

  onOpen(ev: Event): any {
    this.setState({ connected: true })
  }

  onClose(ev: CloseEvent): any {
    console.log(ev)
    this.setState({ connected: false })
    AntMessage.error('连接已断开!')
  }

  onError(ev: Event): any {
    this.setState({ connected: false })
    AntMessage.error('连接错误!')
  }

  onMessage(ev: MessageEvent): any {
    const data: Message = JSON.parse(ev.data)
    switch (data.what) {
      case 'new_chat_msg':
        this.onChatMessage(data)
        break;
      case 'sendMsg':
        //const recvedUsers = parseInt(data.rsp)
        break;
      case 'friend_logged_out':
        this.onFriendLogInOut(data.content, false)
        break;
      case 'friend_logged_in':
        this.onFriendLogInOut(data.content, true)
        break;
      case 'login':
        if (data.rsp === 'true') {
          AntMessage.success(`欢迎回来: ${this.state.nickname}`)
          this.setState({ modalVisible: false })
        } else {
          AntMessage.error('登录失败，昵称重复！')
        }
        break;
      case 'logout':
        if (data.rsp === 'true') {
          this.setState({ modalVisible: true })
          AntMessage.success(`再见: ${this.state.nickname}`)
        } else {
          AntMessage.error('登出失败！')
        }
        break;
      case 'onlineUsers':
        const onlineUsers = parseInt(data.rsp)
        this.showOnlineUsers(onlineUsers)
        break;
    }
  }

  onChatMessage(msg: Message) {
    let data = new Data()
    if (msg.sender === this.state.nickname) {
      data.position = 'right'
    } else {
      data.position = 'left'
    }
    data.type = 'text'
    data.text = msg.content
    data.title = msg.sender
    data.date = new Date(msg.timestamp)
    let avatars = new Avatars(sprites, {
      base64: true
    });
    let avatar = avatars.create(msg.sender);
    data.avatar = avatar.toString()
    this.appendDataToList(data)
  }

  showOnlineUsers(numberOfUsers: number) {
    let text = `共 ${numberOfUsers} 个用户在线`
    let data = new Data()
    data.type = 'system'
    data.text = text
    data.date = new Date()
    this.appendDataToList(data)
  }

  onFriendLogInOut(who: string, isIn: boolean) {
    let text = ''
    if (isIn) {
      text = `${who} 加入了聊天`
    } else {
      text = `${who} 离开了聊天`
    }
    let data = new Data()
    data.type = 'system'
    data.text = text
    data.date = new Date()
    this.appendDataToList(data)
  }

  appendDataToList(data: Data) {
    let dts = this.state.dataSource;
    if (dts.length > 50) {
      dts.shift()
    }
    dts.push(data)
    this.setState({ dataSource: dts })
    document.querySelector<HTMLAnchorElement>('.toBottom')?.scrollIntoView()
  }

  tryLogin() {
    if (!this.state.connected) {
      AntMessage.error('未与服务器连接，请刷新页面！')
      return
    }
    this.sendMessage(new SendMessage('login', this.state.nickname))
  }

  sendChatMessage() {
    if (!this.state.connected) {
      AntMessage.error('未与服务器连接，请刷新页面！')
      return
    }
    let msg = this.state.message
    if (msg.trim().length === 0) {
      return
    }
    var smsg: SendMessage | undefined;
    if (msg.startsWith('/')) {
      switch (msg) {
        case '/logout':
          smsg = new SendMessage('logout', '');
          break;
        case '/users':
          smsg = new SendMessage('onlineUsers', '');
          break;
      }
    } else {
      smsg = new SendMessage('sendMsg', msg)
    }
    if (smsg) {
      this.sendMessage(smsg)
    }
    this.setState({ message: '' })
  }

  sendMessage(msg: SendMessage) {
    websocket?.send(JSON.stringify(msg))
  }
}

export default App;